/**
 * 钩子允许注入的函数必须在结束前顺序完成。
 * 它们将并行执行，但必须完成后才能继续。
 * 如果函数是异步的，可能会返回一个promise
 *
 * Hooks allow for injecting functions that must all complete in order before finishing
 * They will execute in parallel but all must finish before continuing
 * Functions may return a promise if they are asycn.
 * From epubjs/src/utils/hooks
 * 
 * @param {any} context scope of this
 * @example this.content = new Hook(this);
 */
class Hook {
	constructor(context) {
		this.context = context || this;
		this.hooks = [];
	}

	/**
	 * 添加要在钩子完成之前运行的函数
	 *
	 * Adds a function to be run before a hook completes
	 * @example this.content.register(function(){...});
	 * @return {undefined} void
	 */
	register() {
		for (var i = 0; i < arguments.length; ++i) {
			if (typeof arguments[i] === "function") {
				this.hooks.push(arguments[i]);
			} else {
				// unpack array
				for (var j = 0; j < arguments[i].length; ++j) {
					this.hooks.push(arguments[i][j]);
				}
			}
		}
	}

	/**
	 * 触发一个钩子来运行所有函数
	 *
	 * Triggers a hook to run all functions
	 * @example this.content.trigger(args).then(function(){...});
	 * @return {Promise} results
	 */
	trigger() {
		var args = arguments;
		var context = this.context;
		var promises = [];

		this.hooks.forEach(function (task) {
			var executing = task.apply(context, args);

			if (executing && typeof executing["then"] === "function") {
				// Task is a function that returns a promise 任务是一个返回承诺的函数
				promises.push(executing);
			} else {
				// Otherwise Task resolves immediately, add resolved promise with result
				// 否则任务立即解决，添加已解决的承诺和结果
				promises.push(
					new Promise((resolve, reject) => {
						resolve(executing);
					})
				);
			}
		});

		return Promise.all(promises);
	}

	/**
	 * 触发挂钩以同步运行所有函数
	 *
	 * Triggers a hook to run all functions synchronously
	 * @example this.content.trigger(args).then(function(){...});
	 * @return {Array} results
	 */
	triggerSync() {
		var args = arguments;
		var context = this.context;
		var results = [];

		this.hooks.forEach(function (task) {
			var executing = task.apply(context, args);

			results.push(executing);
		});

		return results;
	}

	// Adds a function to be run before a hook completes
	//  添加一个在钩子完成之前运行的函数
	list() {
		return this.hooks;
	}

	clear() {
		return (this.hooks = []);
	}
}
export default Hook;
